#pragma once
#include <vector>
#include <functional>
#include <iostream>
#include <type_traits>

//#define CASE_1
#ifdef CASE_1
template<typename Func>
std::vector<int> operator|(std::vector<int> container, Func&& func) {
    for (auto&& i : container) {
        func(i);
    }
    return container;
}
#endif

#define CASE_2
#ifdef CASE_2
template<typename T, typename Func>
    requires std::invocable<Func, T&>
auto operator|(std::vector<T> container, Func&& func) {
    for (auto&& i : container) {
        func(i);
    }
    return container;
}
#endif

//#define CASE_3
#ifdef CASE_3
template<typename T, typename U>
//requires std::regular_invocable<U, T&&>
auto operator|(T&& container, U&& func) noexcept {
    auto res{ container };
    for (auto& i : container) {
        res[i] = func(i);
    }
    return res;
}
#endif

namespace study1 {

    int main() {
        std::vector v{1, 2, 3};
        std::function f {[](const int& i) {std::cout << i << ' '; } };
        auto f2 = [](int& i) {i *= i; };
        v | f2 | f;

        return 0;
    }

}